<?php

class ABC {
	public static function go () {
		// 不存在命名空间的情况下：
		//		是一个数组，只有一个元素，就是需要的类的类名：
		//		array(1) { [0]=> string(6) "Person" }
		
		// 存在命名空间的情况下：
		//		是一个数组，只有一个元素，就是需要的类的具有命名空间的类名，但把命名空间最前面的 \ 根空间去掉：
		//		array(1) { [0]=> string(21) "app\controller\Person" }
		//		测试时注意：Person.class.php 中记得写上命名空间 namespace app\controller，否则被坑死。
		//		测试时，使用 $obj = new \app\controller\Person(); 和 $obj = new app\controller\Person(); 都一样。
		//		注意：后者 app 前没有 \ 根空间标志。
		//		不过可能由于当前代码就是在根命名空间下写的，所以有没有前面的 \ 都一样。
		//		但是，假如当前 php 文件本代码之前有 namespace ...，效果就不一样了。
		
		$args = func_get_args();
		var_dump($args);

		// 处理命名空间的类，就是根据 \ 进行拆分，组装类文件的路径；
		// 简单点的话，直接用，因为 Windows 也支持 \ 路径。

		// require __DIR__ . DIRECTORY_SEPARATOR . $args[0] . '.class.php';

		require __DIR__ . DIRECTORY_SEPARATOR . $args[0] . '.class.php';

		/*
		兼顾命名空间的类，最好替换命名空间的 \ 分隔符。
		Windows 下测试成功。
		注意：替换的正则需要 3 个 \\\，否则失败。

		$replace = preg_replace('/\\\/', DIRECTORY_SEPARATOR, $args[0]);
		var_dump($replace);
		echo '<br/>';

		$classPath = __DIR__ . DIRECTORY_SEPARATOR . $args[0] . '.class.php';
		echo $classPath;
		echo '<br/>';

		require $classPath;
		*/
	}

}

// 执行 ABC 类的静态方法 go，注册类加载方式。
spl_autoload_register(array('ABC', 'go'), true, true);

// 必须触发一下，才能看到go 方法里面的打印情况。
//$obj = new Person();
/*
内容比较简单
<?php
Class Person {
	public $name = 'H:\www\Person.class.php人';
}
*/
// 如果真的存在并加载成功，则实例化成功，那么 $obj 就是一个实例了。
//var_dump($obj);


// 测试具有命名空间的类的加载
$obj = new \app\controller\Person();
/*
内容比较简单
<?php
namespace app\controller;
Class Person {
	public $name = 'H:\\www\\app\\controller\\Person.class.php人';
}
*/
var_dump($obj);



// 同时存在两个类加载器的情况：
/*
	假如类 ABC 有另一个方法：
	public static function go2 () {
		$args = func_get_args();
		var_dump($args);
		echo '<br/>';
		require 'H:/www/app/controller/Person.class.php';
	}

并且都是按顺序来放置的，也就是第三个参数是 false：
spl_autoload_register(array('ABC', 'go'), true, false);
spl_autoload_register(array('ABC', 'go2'), true, false);


都没有命名空间：
$obj = new Person(); 
就是遇到第一个 Class Person 就会进行实例化，不会报错， 虽然有两个 Person类，但其实只会加载第一个。
	测试了：两个类都有静态方法 go()，调用 Person::go()，当然是第一个 Person 类的 go 方法。
	当把第一个 Person 类的 go 方法去掉，再次执行就报错了：Call to undefined method Person::go()。
	虽然此时第二个 Person 类有 go 方法，但不会加载这个类。
	这就是类加载器的一个特性，也避免了重复定义类的错误。

	另外，在研究 laravel 的源码时，看到有在类的加载器内返回 true的情况，于是测试了下：
	不管是return true 还是 false，结果没变化。
	看源码，暂时也没发现这个返回值干啥用了~
$obj = new \app\controller\Person(); 
	ABC 类的 go 和 go2 方法都会执行，
	因为使用第一个类的加载器 go 找到了指定位置的文件，虽然类名一致，但由于没有命名空间，所以不符合 new 的条件；
	于是会继续使用第二个类的加载器 go2 又找到了同一个位置的文件，又加载进来，都没有命名空间，类名又重复，自然就报错了：
	Cannot redeclare class Person in H:\www\app\controller\Person.class.php。

第一个没有命名空间，第二个有命名空间：
$obj = new Person(); 
	当然是第一个；成功；
$obj = new \app\controller\Person(); 
	当然是第二个；成功；

第一个有命名空间，第二个没有命名空间：
$obj = new Person(); 
	当然是第二个；成功；
$obj = new \app\controller\Person(); 
	Cannot redeclare class Person in H:\www\app\controller\Person.class.php
	因为第一次使用 go，找到了第二个 Person 类，但由于没有命名空间，所以不符合条件；
	接着第二次使用 go2，还是找第二个 Person 类，加载两次，都没有命名空间，就是重复定义了。

都有命名空间：
$obj = new Person(); 
	Cannot redeclare class app\controller\Person in H:\www\app\controller\Person.class.php
	使用 go，找到了第一个带有命名空间的 Person，不符合条件；
	使用 go2，找打了第二个带有命名空间的 Person，两个Person 都有同一个命名空间，虽然文件路径不同，但也重复定义了。
$obj = new \app\controller\Person(); 
	当然是第二个；成功；
*/